/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package plash.display;

import java.util.ArrayList;
import plash.geom.Point;
import plash.geom.Rectangle;
import processing.core.PGraphics;

/**
 *
 * @author #0K Srinivasan <hashok.com>
 */
public class Graphics implements IDrawable, IGraphicPainter
{
    protected boolean __maskedPainting = false;
    protected Rectangle __boundingBox = new Rectangle();
    protected PGraphics __painter;
    protected DisplayObject __owner;
    protected ArrayList<IGraphicCommand> __commands;

    public Graphics(DisplayObject owner)
    {
        __owner = owner;
        _init();
    }

    private void _init()
    {
        __commands = new ArrayList<IGraphicCommand>();
        __commands.add(new GraphicStroke(this, 0, 0x000000, 0));
        __commands.add(new GraphicFill(this, 0x000000, 0));
    }

    private void _updateBoundingbox()
    {
        if (__commands.size() < 1)
        {
            return;
        }

        for (IGraphicCommand command : __commands)
        {
            if (command instanceof IGraphicShape)
            {
                __boundingBox = __boundingBox.union(((IGraphicShape) command).boundingBox());
            }
        }
    }

    @Override
    public void draw()
    {
        if(this.getOwner().getPainter() == null)
        {
            return;
        }
        if (__commands.size() < 1)
        {
            return;
        }

        for (IGraphicCommand command : __commands)
        {
            command.execute();
        }
    }

    @Override
    public void clear()
    {
        __commands.clear();
        __commands.add(new GraphicStroke(this, 0, 0x000000, 0));
        __commands.add(new GraphicFill(this, 0x000000, 0));
    }

    @Override
    public void setLineStyle(int thickness, int color, float alpha)
    {
        __commands.add(new GraphicStroke(this, thickness, color, alpha * __owner.getAbsoluteAlpha()));
    }

    @Override
    public void beginFill(int hexaColor, float alpha)
    {
        __commands.add(new GraphicFill(this, hexaColor, alpha * __owner.getAbsoluteAlpha()));
    }

    @Override
    public void endFill()
    {
        __commands.add(new GraphicFill(this, 0xFFFFFF, 0));
        __commands.add(new GraphicStroke(this, 1, 0xFFFFFF, 0));
    }

    @Override
    public void moveTo(int x, int y)
    {
        GraphicLinearPathShape command = new GraphicLinearPathShape(this);
        command.addToPath(new Point(x, y));
        __commands.add(command);
    }

    @Override
    public void lineTo(int x, int y)
    {
        Point lastPoint;
        GraphicLinearPathShape lineShape;

        IGraphicCommand lastCommand = __commands.get(__commands.size() - 1);

        if (lastCommand instanceof GraphicCurvePathShape)
        {
            lastPoint = ((GraphicCurvePathShape) lastCommand).getLastPoint();
            lineShape = new GraphicLinearPathShape(this);
            lineShape.addToPath(lastPoint);
            lineShape.addToPath(new Point(x, y));
        }
        else if (lastCommand instanceof GraphicLinearPathShape)
        {
            ((GraphicLinearPathShape) lastCommand).addToPath(new Point(x, y));
        }
        else
        {
            lineShape = new GraphicLinearPathShape(this);
            lineShape.addToPath(new Point());
            lineShape.addToPath(new Point(x, y));
            __commands.add(lineShape);
        }
    }

    @Override
    public void curveTo(int cx, int cy, int ax, int ay)
    {
        Point lastPoint;
        GraphicCurvePathShape curveShape;
        IGraphicCommand lastCommand = __commands.get(__commands.size() - 1);

        if (lastCommand instanceof GraphicCurvePathShape)
        {
            ((GraphicCurvePathShape) lastCommand).addToPath(new Point(ax, ay));
            ((GraphicCurvePathShape) lastCommand).addControlPoint(new Point(cx, cy));
        }
        else if (lastCommand instanceof GraphicLinearPathShape)
        {
            lastPoint = ((GraphicLinearPathShape) lastCommand).getLastPoint();
            curveShape = new GraphicCurvePathShape(this);
            curveShape.addToPath(lastPoint);
            curveShape.addToPath(new Point(ax, ay));
            curveShape.addControlPoint(new Point(cx, cy));
            __commands.add(curveShape);
        }
        else
        {
            curveShape = new GraphicCurvePathShape(this);
            curveShape.addToPath(new Point());
            curveShape.addToPath(new Point(ax, ay));
            curveShape.addControlPoint(new Point(cx, cy));
            __commands.add(curveShape);
        }
    }

    @Override
    public void drawCircle(int x, int y, int radius)
    {
        __commands.add(new GraphicOvalShape(this, x, y, radius));
    }

    @Override
    public void drawEllipse(int x, int y, int radiusX, int radiusY)
    {
        __commands.add(new GraphicOvalShape(this, x, y, radiusX, radiusY));
    }

    @Override
    public void drawRectangle(int x, int y, int width, int height)
    {
        __commands.add(new GraphicRectangleShape(this, x, y, width, height));
    }

    @Override
    public void drawRectangle(Rectangle rectangle)
    {
        drawRectangle(rectangle.getX(), rectangle.getY(), rectangle.getWidth(), rectangle.getHeight());
    }

    @Override
    public void drawRoundedRectangle(int x, int y, int width, int height, int ellipseWidth, int ellipseHeight)
    {
        __commands.add(new GraphicRectangleShape(this, x, y, width, height, ellipseWidth, ellipseHeight));
    }

    @Override
    public void drawRoundedRectangleComplex(int x, int y, int width, int height,
                                            int topLeftRadius, int topRightRadius,
                                            int bottomLeftRadius, int bottomRightRadius)
    {
        __commands.add(new GraphicRectangleShape(this, x, y, width, height, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius));
    }

    @Override
    public void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3)
    {
        __commands.add(new GraphicTriangle(this, x1, y1, x2, y2, x3, y3));
    }

    @Override
    public void drawTriangle(Point p1, Point p2, Point p3)
    {
        __commands.add(new GraphicTriangle(this, p1, p2, p3));
    }

    @Override
    public void drawArc(int x, int y, int radius, int startAngle, int endAngle)
    {
        __commands.add(new GraphicArc(this, x, y, radius, startAngle, endAngle));
    }

    public PGraphics getPainter()
    {
        return __painter;
    }

    public void setPainter(PGraphics painter)
    {
        this.__painter = painter;
    }

    public Rectangle getBoundingBox()
    {
        _updateBoundingbox();

        return __boundingBox;
    }

    public DisplayObject getOwner()
    {
        return __owner;
    }
}
